import { expect } from 'chai';
import * as sinon from 'sinon';
import { validateTemplate } from '../src/validateTemplate';
import * as step from '@flow-step/step-toolkit';
import * as getTemplateModule from '../src/getTemplate';
import { ValidateTemplateRequest } from '@alicloud/ros20190910';

describe('validateTemplate', () => {
  let sandbox: sinon.SinonSandbox;
  let mockRos: any;
  let mockParams: any;
  let stepErrorStub: sinon.SinonStub;
  let getTemplateBodyStub: sinon.SinonStub;

  beforeEach(() => {
    sandbox = sinon.createSandbox();
    mockRos = {
      validateTemplate: sandbox.stub()
    };
    mockParams = {
      REGION_ID: 'cn-hangzhou',
      STACK_NAME: 'test-stack',
      pipelineID: 123,
      pipelineName: 'test-pipeline',
      workSpace: '/test/workspace',
      projectDir: '/test/project',
      buildJobID: 456,
      ROS_DEPLOYMENT_LOCATION: 'cn',
      RAM_ROLE_NAME: 'test-role',
      ROS_STACK_FILE_PATH: 'template.json',
      TIMEOUT_MINUTES: 60
    };
    stepErrorStub = sandbox.stub(step, 'error');
    getTemplateBodyStub = sandbox.stub(getTemplateModule, 'getTemplateBody');
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('should return true when template validation succeeds', async () => {
    const mockTemplate = '{"Resources": {"Test": {"Type": "ALIYUN::ECS::Instance"}}}';
    getTemplateBodyStub.returns(mockTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.true;
    expect(mockRos.validateTemplate.calledOnce).to.be.true;
  });

  it('should construct correct ValidateTemplateRequest', async () => {
    const mockTemplate = '{"Resources": {}}';
    getTemplateBodyStub.returns(mockTemplate);
    mockRos.validateTemplate.resolves({});

    await validateTemplate(mockParams, mockRos);

    const call = mockRos.validateTemplate.getCall(0);
    const request = call.args[0];
    
    expect(request.regionId).to.equal('cn-hangzhou');
    expect(request.templateBody).to.equal(mockTemplate);
    expect(request).to.be.instanceOf(ValidateTemplateRequest);
  });

  it('should handle validation API errors gracefully', async () => {
    const mockTemplate = '{"Invalid": "template"}';
    const mockError = {
      code: 'InvalidTemplate',
      data: {
        Message: 'Template format error',
        RequestId: 'req-123'
      }
    };

    getTemplateBodyStub.returns(mockTemplate);
    mockRos.validateTemplate.rejects(mockError);

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.false;
    expect(stepErrorStub.calledWith('Failed to ValidateTemplate. Code: InvalidTemplate, Message: Template format error, RequestId: req-123')).to.be.true;
  });

  it('should handle unexpected errors without message', async () => {
    const mockTemplate = '{"test": "template"}';
    const mockError = {
      code: 'UnknownError'
    };

    getTemplateBodyStub.returns(mockTemplate);
    mockRos.validateTemplate.rejects(mockError);

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.false;
    expect(stepErrorStub.calledWith('Failed to ValidateTemplate. Code: UnknownError, Message: undefined, RequestId: undefined')).to.be.true;
    expect(stepErrorStub.calledWith('Unexpected ValidateTemplate error. Error: {\n  "code": "UnknownError"\n}')).to.be.true;
  });

  it('should handle complex template validation', async () => {
    const complexTemplate = JSON.stringify({
      ROSTemplateFormatVersion: '2015-09-01',
      Parameters: {
        InstanceType: {
          Type: 'String',
          Default: 'ecs.t5-lc1m1.small'
        }
      },
      Resources: {
        WebServer: {
          Type: 'ALIYUN::ECS::Instance',
          Properties: {
            ImageId: 'centos_7_04_64_20G_alibase_201701015.vhd',
            InstanceType: { Ref: 'InstanceType' }
          }
        }
      }
    });

    getTemplateBodyStub.returns(complexTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.true;
    expect(mockRos.validateTemplate.calledOnce).to.be.true;
  });

  it('should handle YAML template validation', async () => {
    const yamlTemplate = `
ROSTemplateFormatVersion: '2015-09-01'
Resources:
  WebServer:
    Type: ALIYUN::ECS::Instance
    Properties:
      ImageId: centos_7_04_64_20G_alibase_201701015.vhd
      InstanceType: ecs.t5-lc1m1.small
`;

    getTemplateBodyStub.returns(yamlTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.true;
  });

  it('should handle empty template body', async () => {
    const emptyTemplate = '';
    getTemplateBodyStub.returns(emptyTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.true;
  });

  it('should handle template with syntax errors', async () => {
    const invalidTemplate = '{"Resources": {"Test": {"Type": "InvalidType"}}}';
    const mockError = {
      code: 'InvalidResourceType',
      data: {
        Message: 'Invalid resource type: InvalidType',
        RequestId: 'req-456'
      }
    };

    getTemplateBodyStub.returns(invalidTemplate);
    mockRos.validateTemplate.rejects(mockError);

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.false;
    expect(stepErrorStub.calledWith('Failed to ValidateTemplate. Code: InvalidResourceType, Message: Invalid resource type: InvalidType, RequestId: req-456')).to.be.true;
  });

  it('should handle different region IDs', async () => {
    const mockTemplate = '{"Resources": {}}';
    const paramsWithDifferentRegion = {
      REGION_ID: 'us-west-1',
      STACK_NAME: 'test-stack',
      pipelineID: 123,
      pipelineName: 'test-pipeline',
      workSpace: '/test/workspace',
      projectDir: '/test/project',
      buildJobID: 456,
      ROS_DEPLOYMENT_LOCATION: 'cn',
      RAM_ROLE_NAME: 'test-role',
      ROS_STACK_FILE_PATH: 'template.json',
      TIMEOUT_MINUTES: 60
    };
    
    getTemplateBodyStub.returns(mockTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(paramsWithDifferentRegion, mockRos);

    expect(result).to.be.true;
    const call = mockRos.validateTemplate.getCall(0);
    expect(call.args[0].regionId).to.equal('us-west-1');
  });

  it('should handle large template validation', async () => {
    const largeTemplate = JSON.stringify({
      ROSTemplateFormatVersion: '2015-09-01',
      Resources: Array(100).fill(0).reduce((acc, _, i) => {
        acc[`Resource${i}`] = {
          Type: 'ALIYUN::ECS::Instance',
          Properties: {
            ImageId: 'centos_7',
            InstanceType: 'ecs.t5.small'
          }
        };
        return acc;
      }, {})
    });

    getTemplateBodyStub.returns(largeTemplate);
    mockRos.validateTemplate.resolves({});

    const result = await validateTemplate(mockParams, mockRos);

    expect(result).to.be.true;
  });
});